{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\SZU\\Anaconda3\\lib\\site-packages\\h5py\\__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n",
      "  from ._conv import register_converters as _register_converters\n",
      "Using TensorFlow backend.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Load data.....\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import sys\n",
    "import numpy as np\n",
    "from sklearn.model_selection import train_test_split\n",
    "from keras.preprocessing import image\n",
    "print('Load data.....')\n",
    "parapath = './dataset/Parasitized/'\n",
    "uninpath = './dataset/Uninfected/'\n",
    "parastized = os.listdir(parapath)\n",
    "uninfected = os.listdir(uninpath)\n",
    "data = []\n",
    "label = []\n",
    "for para in parastized:\n",
    "    try:\n",
    "        img =  image.load_img(parapath+para,target_size=(128,128))\n",
    "        x = image.img_to_array(img)\n",
    "        data.append(x)\n",
    "        label.append(1)\n",
    "    except:\n",
    "        print(\"Can't add \"+para+\" in the dataset\")\n",
    "for unin in uninfected:\n",
    "    try:\n",
    "        img =  image.load_img(uninpath+unin,target_size=(128,128))\n",
    "        data.append(x)\n",
    "        label.append(0)\n",
    "    except:\n",
    "        print(\"Can't add \"+unin+\" in the dataset\")  \n",
    "data = np.array(data)\n",
    "label = np.array(label)\n",
    "data = data/255\n",
    "x_train, x_test, y_train, y_test = train_test_split(data,label,test_size = 0.2,random_state=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "#!/usr/bin/env python\n",
    "# -*- coding: utf-8 -*-\n",
    "\"\"\"\n",
    "@Author:ChileWang\n",
    "@Created On 2019-06-21\n",
    "@Coding Environment: Anaconda Python 3.7\n",
    "\"\"\"\n",
    "import random\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd\n",
    "import keras\n",
    "from keras.preprocessing.image import ImageDataGenerator\n",
    "from keras.models import Sequential, Model\n",
    "from keras.layers import Dense, Dropout, Activation, Flatten\n",
    "from keras.layers import Conv2D, MaxPooling2D\n",
    "import os\n",
    "from keras.layers import LeakyReLU\n",
    "from keras.layers import PReLU\n",
    "import operator\n",
    "from keras.models import load_model\n",
    "import copy\n",
    "from keras.utils import multi_gpu_model\n",
    "from keras.layers.normalization import BatchNormalization\n",
    "os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0\"  # 指定占用模块GPU，若不指定，将会占用所有GPU。\n",
    "# Save model and weights\n",
    "save_dir = os.path.join(os.getcwd(), 'saved_models_cnn')\n",
    "if not os.path.isdir(save_dir):\n",
    "        os.makedirs(save_dir)\n",
    "\n",
    "class GeneticAlgorithm:\n",
    "    # -----------初始数据定义---------------------\n",
    "    # 定义一些遗传算法需要的参数\n",
    "    #     JCL = 0.9  # 遗传时的交叉率\n",
    "    #     BYL = 0.09  # 遗传时的变异率\n",
    "\n",
    "    def __init__(self, rows, times, num_classes, kill_num):\n",
    "        self.rows = rows  # 染色体个数\n",
    "        self.times = times  # 迭代次数\n",
    "        self.accuracy = 0  # 模型准确率\n",
    "        self.layer_list = ['Conv2D', 'Dense']  # 算法使用的网络层\n",
    "        self.cnn_activation_function =  ['linear', 'leaky relu', 'prelu', 'relu']  # CNN层用到激励函数\n",
    "        self.dense_activation_function = ['linear', 'sigmoid', 'softmax', 'relu']  # 中间全连接层用到的激励函数\n",
    "        self.last_dense_activation_function = ['sigmoid', 'softmax']  # 最后一个全连接层用到的激励函数\n",
    "        self.unit_num_list = [64, 128, 256]    # 神经元数目选择\n",
    "        self.filter_num_list = [4, 8, 16]  # 卷积核数目选择\n",
    "        self.pooling_size = range(2, 4)  # max_pooling的选择范围\n",
    "        self.filter_size = range(2, 4)  # 卷积核的选择范围\n",
    "        self.layer_num_list = range(2, 4)  # 网络层次的选择范围 \n",
    "        self.max_size = 10  # 层数最大值\n",
    "        self.threshold = 3  # 层数临界值\n",
    "        self.batch_size = 512\n",
    "        self.num_classes = num_classes  # 2分类\n",
    "        self.kill_num = kill_num  # 每次杀掉的网络个数\n",
    "\n",
    "    # -------------遗传函数开始执行---------------------\n",
    "    def run(self):\n",
    "\n",
    "        print(\"开始迭代\")\n",
    "        # 初始化种群\n",
    "        lines = [self.create_network(self.create_chromosome()) for i in range(self.rows)]\n",
    "\n",
    "        # 初始化种群适应度\n",
    "        fit = [0 for i in range(self.rows)]\n",
    "\n",
    "        epochs = 1\n",
    "        # 计算每个染色体(网络)的适应度\n",
    "        for i in range(0, self.rows):\n",
    "            lines[i]['is_saved'] = False\n",
    "            lines[i]['model_name'] = 'model_%s' % str(i)\n",
    "            lines[i] = self.cal_fitness(lines[i], epochs)\n",
    "            fit[i] = lines[i]['fitness']\n",
    "\n",
    "        # 开始迭代\n",
    "        t = 0\n",
    "        while t < self.times:\n",
    "            print('迭代次数:', t)\n",
    "            random_fit = [0 for i in range(self.rows)]\n",
    "            total_fit = 0\n",
    "            tmp_fit = 0\n",
    "\n",
    "            # 开始遗传\n",
    "            # 根据轮盘赌选择复代\n",
    "            # 计算原有种群的总适应度\n",
    "            for i in range(self.rows):\n",
    "                total_fit += fit[i]\n",
    "            # 通过适应度占总适应度的比例生成随机适应度\n",
    "            for i in range(self.rows):\n",
    "                    random_fit[i] = tmp_fit + fit[i] / total_fit\n",
    "                    tmp_fit += random_fit[i]\n",
    "            r = int(self.random_select(random_fit))\n",
    "            line = lines[r]\n",
    "\n",
    "            # 不需要交叉的，直接变异，然后遗传到下一代\n",
    "            # 基因变异, 生成两个子代\n",
    "            print('*******变异******')\n",
    "            offspring1 = self.mutation(line, 'offspring1')\n",
    "            offspring2 = self.mutation(offspring1, 'offspring2')\n",
    "            best_chromosome = self.get_best_chromosome(line, offspring1, offspring2, epochs)\n",
    "            # 替换原先的父代\n",
    "            father_model_name = lines[r]['model_name']\n",
    "            lines[r] = best_chromosome\n",
    "            print('保存最佳变异个体。。。。')\n",
    "            # 保存模型\n",
    "            model_path = os.path.join(save_dir, father_model_name)\n",
    "            lines[r]['model_path'] = model_path  # 每一个模型的路径\n",
    "            lines[r]['is_saved'] = True  # 是否保存\n",
    "            best_chromosome_model = lines[r]['model'] \n",
    "            best_chromosome_model.save(model_path)\n",
    "            \n",
    "            epochs += 1\n",
    "            # 杀掉最差的self.kill_num个网络\n",
    "            kill_index = 1\n",
    "            sorted_lines = sorted(lines, key=operator.itemgetter('fitness'))  # 按适应度从小到大排序\n",
    "            if len(sorted_lines) > self.kill_num:\n",
    "                # 第一次迭代杀死适应度小于0.55的网络\n",
    "                for i in range(len(sorted_lines)):\n",
    "                    if sorted_lines[i]['fitness'] < 0.55:\n",
    "                        kill_index = i\n",
    "                    else:\n",
    "                        break\n",
    "                if t == 0:\n",
    "                    new_lines = sorted_lines[kill_index:]\n",
    "                    self.rows -= kill_index\n",
    "                else:\n",
    "                    new_lines = sorted_lines[self.kill_num:]\n",
    "                    self.rows -= self.kill_num\n",
    "                lines = new_lines  # 更新种群\n",
    "                next_fit = [line['fitness'] for line in lines]  # 更新种群\n",
    "                fit = next_fit          \n",
    "                # self.rows -= self.kill_num\n",
    "                print('..........Population size:%d .........' % self.rows)\n",
    "           \n",
    "            # 进行新的一次epochs，计算种群的适应度\n",
    "            # 计算每个染色体(网络)的适应度\n",
    "            for i in range(0, self.rows):\n",
    "                lines[i] = self.cal_fitness(lines[i], 1)\n",
    "                fit[i] = lines[i]['fitness']\n",
    "            print('***************************************************')\n",
    "            print()\n",
    "            t += 1  # 代数+1\n",
    "\n",
    "        # 提取适应度最高的\n",
    "        m = fit[0]\n",
    "        ml = 0\n",
    "        for i in range(self.rows):\n",
    "            if m < fit[i]:\n",
    "                m = fit[i]\n",
    "                ml = i\n",
    "\n",
    "        print(\"迭代完成\")\n",
    "        # 输出结果:\n",
    "        excellent_chromosome = self.cal_fitness(lines[ml], 0)\n",
    "        print('The best network:')\n",
    "        print(excellent_chromosome['model'].summary())\n",
    "        print('Fitness: ', excellent_chromosome['fitness'])\n",
    "        print('Accuracy', excellent_chromosome['accuracy'])\n",
    "        \n",
    "        best_model_save_dir = os.path.join(os.getcwd(), 'best_model')\n",
    "        if not os.path.isdir(best_model_save_dir):\n",
    "            os.makedirs(best_model_save_dir)\n",
    "        best_model_path = os.path.join(best_model_save_dir, 'excellent_model')\n",
    "        excellent_chromosome['model'].save(best_model_path)\n",
    "        print(excellent_chromosome['layer_list'])\n",
    "        with open('best_network_layer_list.txt', 'w') as fw:\n",
    "            for layer in excellent_chromosome['layer_list']:\n",
    "                fw.write(str(layer) + '\\n')\n",
    "        \n",
    "\n",
    "    # -----------------遗传函数执行完成--------------------\n",
    "\n",
    "    # -----------------各种辅助计算函数--------------------\n",
    "    def create_network(self, chromsome_dict):\n",
    "        \"\"\"\n",
    "        :param chromosome:\n",
    "        :return:\n",
    "        \"\"\"\n",
    "        layer_list = chromsome_dict['layer_list']\n",
    "        layer_num = chromsome_dict['layer_num'] + 2  # 包括输入输出\n",
    "        unit_num_sum = 0  # 统计Dense神经元的个数\n",
    "        model = Sequential()\n",
    "        for i in range(len(layer_list) - 1):\n",
    "            if i == 0:\n",
    "                model.add(Conv2D(layer_list[i]['conv_kernel_num'],\n",
    "                                 layer_list[i]['conv_kernel_size'],\n",
    "                                 padding=layer_list[i]['padding'],\n",
    "                                 input_shape=layer_list[i]['input_shape'],\n",
    "                                 kernel_initializer='he_normal'\n",
    "                                 )\n",
    "                          )\n",
    "                model = self.add_activation_funtion(model, layer_list[i]['layer_activation_function'])\n",
    "\n",
    "            else:\n",
    "                if layer_list[i]['layer_name'] == 'Conv2D':\n",
    "                    model.add(Conv2D(layer_list[i]['conv_kernel_num'],\n",
    "                                     layer_list[i]['conv_kernel_size'],\n",
    "                                     padding=layer_list[i]['padding'],\n",
    "                                     )\n",
    "                              )\n",
    "                    model = self.add_activation_funtion(model, layer_list[i]['layer_activation_function'])\n",
    "\n",
    "                    if layer_list[i]['pooling_choice']:  # 是否创建Pooling层次\n",
    "                        try:\n",
    "                            model.add(MaxPooling2D(pool_size=layer_list[i]['pool_size'], dim_ordering=\"tf\"))\n",
    "                        except Exception as error:\n",
    "                            print('MaxPooling大于输入的矩阵, 用pool_size=(1, 1)代替')\n",
    "                            model.add(MaxPooling2D(pool_size=(1, 1), strides = (2, 2)))\n",
    "                        layer_num += 1\n",
    "                        model.add(BatchNormalization())\n",
    "\n",
    "                    # Dropout层\n",
    "                    model.add(Dropout(layer_list[i]['dropout_rate']))\n",
    "\n",
    "                else:  # Dense层\n",
    "                    unit_num_sum += layer_list[i]['unit_num']\n",
    "                    model.add(Dense(layer_list[i]['unit_num'],\n",
    "                                    )\n",
    "                              )\n",
    "                    model = self.add_activation_funtion(model, layer_list[i]['layer_activation_function'])\n",
    "                    # Dropout层\n",
    "                    model.add(Dropout(layer_list[i]['dropout_rate']))\n",
    "\n",
    "        # 最后一层\n",
    "        model.add(Flatten())\n",
    "\n",
    "        if layer_list[-1]['layer_activation_function'] == 'sigmoid':\n",
    "            model.add(Dense(1))\n",
    "            unit_num_sum += 1\n",
    "        else:\n",
    "            model.add(Dense(self.num_classes))\n",
    "            unit_num_sum += self.num_classes\n",
    "        model = self.add_activation_funtion(model, layer_list[-1]['layer_activation_function'])\n",
    "        chromsome_dict['model'] = model\n",
    "        chromsome_dict['punish_factor'] = (1 / layer_num) + (1 / unit_num_sum)  # 惩罚因子\n",
    "        return chromsome_dict\n",
    "\n",
    "    def add_activation_funtion(self, model, activation_name):\n",
    "        \"\"\"\n",
    "        添加激活函数\n",
    "        :param model:\n",
    "        :param activation_name:\n",
    "        :return:\n",
    "        \"\"\"\n",
    "        if activation_name == 'leaky relu':\n",
    "            model.add(LeakyReLU())\n",
    "        elif activation_name == 'prelu':\n",
    "            model.add(PReLU())\n",
    "        else:\n",
    "            model.add(Activation(activation_name))\n",
    "        return model\n",
    "\n",
    "    def create_chromosome(self):\n",
    "        \"\"\"\n",
    "        创建染色体\n",
    "        \"\"\"\n",
    "        chromsome_dict = dict()  # 用字典装载染色体的所有属性\n",
    "        chromsome_dict['learning_rate'] = self.random_learning_rate()  # 学习率\n",
    "        layer_num = random.choice(self.layer_num_list)  # 创建的网络层次， 输入层和输出层不计算在内\n",
    "        chromsome_dict['layer_num'] = layer_num\n",
    "\n",
    "        layer_list = list()  # 网络层次顺序表\n",
    "        # 第一层必须是卷积层\n",
    "        layer_list.append({'layer_name': 'Conv2D',\n",
    "                           'conv_kernel_num': 32,\n",
    "                           'conv_kernel_size': (3, 3),\n",
    "                           'padding': 'same',\n",
    "                           'input_shape': (128, 128, 3),\n",
    "                           'layer_activation_function': random.choice(self.cnn_activation_function)}\n",
    "                          )\n",
    "        # 每一层的属性\n",
    "        for i in range(layer_num):\n",
    "            # 选择层次类型\n",
    "#             layer_name = self.layer_list[random.randint(0, 1)]\n",
    "            layer_name = 'Conv2D'\n",
    "            if i == 0:  # 第一层dropout_rate 必须为0,即不存在\n",
    "                layer_dict = self.create_layer(layer_name)\n",
    "                layer_dict['dropout_rate'] = 0\n",
    "\n",
    "            else:\n",
    "                layer_dict = self.create_layer(layer_name)\n",
    "            layer_list.append(layer_dict)  # 添加至层次列表\n",
    "\n",
    "        # 最后一层必须是Dense层\n",
    "        layer_list.append({'layer_name': 'Dense',\n",
    "                          'layer_activation_function': random.choice(self.last_dense_activation_function)\n",
    "                          }\n",
    "                         )\n",
    "\n",
    "        # 将网络层次顺序表添加至染色体\n",
    "        chromsome_dict['layer_list'] = layer_list\n",
    "\n",
    "        return chromsome_dict\n",
    "\n",
    "    def create_layer(self, layer_name):\n",
    "        \"\"\"\n",
    "        创建网络层次属性\n",
    "        \"\"\"\n",
    "        layer_dict = dict()\n",
    "        layer_dict['layer_name'] = layer_name\n",
    "        if layer_name == 'Conv2D':\n",
    "            # 激励函数\n",
    "            layer_activation_function = random.choice(self.cnn_activation_function)\n",
    "            # 卷积核数量和大小\n",
    "            conv_kernel_num = random.choice(self.filter_num_list)\n",
    "            random_size = random.choice(self.filter_size)\n",
    "            conv_kernel_size = (random_size, random_size)\n",
    "            # 是否加入Pooling层\n",
    "            pooling_choice = [True, False]\n",
    "            if pooling_choice[random.randint(0, 1)]:\n",
    "                layer_dict['pooling_choice'] = True\n",
    "                random_size = random.choice(self.pooling_size)\n",
    "                pool_size = (random_size, random_size)\n",
    "                layer_dict['pool_size'] = pool_size\n",
    "            else:\n",
    "                layer_dict['pooling_choice'] = False\n",
    "\n",
    "            layer_dict['layer_activation_function'] = layer_activation_function\n",
    "            layer_dict['conv_kernel_num'] = conv_kernel_num\n",
    "            layer_dict['conv_kernel_size'] = conv_kernel_size\n",
    "            layer_dict['padding'] = 'same'\n",
    "\n",
    "        else:  # Dense层\n",
    "            # 激励函数\n",
    "            layer_activation_function = random.choice(self.dense_activation_function)\n",
    "            # 神经元个数\n",
    "            unit_num = random.choice(self.unit_num_list)\n",
    "            layer_dict['layer_activation_function'] = layer_activation_function\n",
    "            layer_dict['unit_num'] = unit_num\n",
    "        layer_dict['dropout_rate'] = round(random.uniform(0, 1), 3)\n",
    "        return layer_dict\n",
    "\n",
    "    def cal_fitness(self, line, epochs):\n",
    "        \"\"\"\n",
    "        :param line: 染色体（网络）\n",
    "        :param epochs: 迭代次数\n",
    "        :return:\n",
    "        \"\"\"\n",
    "        if epochs == 0:\n",
    "            return line\n",
    "        line = self.train_process(line, epochs)\n",
    "        # 适应度函数，表示准确率 + 训练参数个数的倒数， 适应度越大，说明模型越好。\n",
    "        # fitness = line['accuracy'] + line['punish_factor']\n",
    "        fitness = line['accuracy'] \n",
    "        line['fitness'] = fitness\n",
    "        return line\n",
    "\n",
    "    def train_process(self, line, epochs):\n",
    "        \"\"\"\n",
    "        训练\n",
    "        :param line: 染色体\n",
    "        :param epochs: 迭代次数\n",
    "        :return:\n",
    "        \"\"\"\n",
    "        \n",
    "        print('learning_rate:', line['learning_rate'])\n",
    "        print('layer_num:', len(line['layer_list']))\n",
    "        \n",
    "        if line['is_saved']:  # 若保存，则直接读入训练即可\n",
    "            print('读取原有模型训练..............')\n",
    "            model_path = line['model_path']\n",
    "            model = load_model(model_path)\n",
    "            accuracy = model.evaluate(x = x_test,y = y_test)[1]\n",
    "            print('former accuracy:', accuracy)\n",
    "        else:\n",
    "            print('重新训练.......')\n",
    "            model = line['model']\n",
    "            learning_rate = line['learning_rate']\n",
    "            # 初始化adam优化器\n",
    "            opt = keras.optimizers.Adam(lr=learning_rate, beta_1=0.9, beta_2=0.999,\n",
    "                                        epsilon=None, decay=1e-6, amsgrad=False)\n",
    "            # 编译模型\n",
    "            layer_list = line['layer_list']\n",
    "            if layer_list[-1]['layer_activation_function'] == 'softmax':\n",
    "                loss = 'sparse_categorical_crossentropy'\n",
    "            else:\n",
    "                loss = 'binary_crossentropy'\n",
    "            print(loss)\n",
    "            model.compile(loss=loss,\n",
    "                          optimizer=opt,\n",
    "                          metrics=['accuracy'])\n",
    "\n",
    "        history = model.fit(x_train, y_train,epochs=epochs, batch_size=self.batch_size)\n",
    "        # Score trained model.\n",
    "        accuracy = model.evaluate(x = x_test,y = y_test)[1]\n",
    "        line['accuracy'] = accuracy\n",
    "        line['history'] = history  # 训练历史\n",
    "        print('accuracy:', accuracy)\n",
    "        # 保存模型\n",
    "        model_name = line['model_name']\n",
    "        model_path = os.path.join(save_dir, model_name)\n",
    "        line['model_path'] = model_path  # 每一个模型的路径\n",
    "        line['is_saved'] = True  # 是否保存\n",
    "        line['model'] = model\n",
    "        model.save(model_path)\n",
    "    \n",
    "        return line\n",
    "\n",
    "    def mutation(self, line, name):\n",
    "        \"\"\"\n",
    "        基因变异\n",
    "        :param line:\n",
    "        :return:\n",
    "        \"\"\"\n",
    "        offspring1 = copy.deepcopy(line) # 深拷贝！！！！子代1\n",
    "        offspring1['model_name'] = name\n",
    "        offspring1['is_saved'] = False\n",
    "        mutation_choice = [True, False]\n",
    "        # 子代1变异\n",
    "        if mutation_choice[random.randint(0, 1)]:  # 改变学习率\n",
    "            print('Mutation Operation: Change learning rate....')\n",
    "            offspring1['learning_rate'] = self.random_learning_rate()  # 学习率\n",
    "        else:  # 改变网络结构\n",
    "            offspring1 = self.layer_mutation_operation(offspring1)\n",
    "        offspring1 = self.create_network(offspring1)\n",
    "        return offspring1\n",
    "\n",
    "    def layer_mutation_operation(self, offspring):\n",
    "        \"\"\"\n",
    "        :param offspring: 子代染色体\n",
    "        :return:\n",
    "        \"\"\"\n",
    "        mutation_layer_choice = [0, 1, 2]  # 添加，替换，删除\n",
    "        mutation_layer_choice_name = ['Add', 'Replace', 'Delete']\n",
    "        layer_name = self.layer_list[random.randint(0, 1)]\n",
    "        layer_dict = self.create_layer(layer_name)\n",
    "        choice_index = -1\n",
    "        if self.threshold < offspring['layer_num'] < self.max_size:  # 层数小于最大值且大于临界值，则可以添加和替换和删除\n",
    "            choice_index = random.randint(0, 2)\n",
    "            if mutation_layer_choice[choice_index] == 0:  # 添加\n",
    "                insert_index = random.randint(1, len(offspring['layer_list']) - 1)  # 插入位置\n",
    "                offspring['layer_list'].insert(insert_index, layer_dict)\n",
    "                offspring['layer_num'] += 1\n",
    "\n",
    "            elif mutation_layer_choice[choice_index] == 1:    # 替换\n",
    "                replace_index = random.randint(1, len(offspring['layer_list']) - 1)  # 替换位置\n",
    "                offspring['layer_list'][replace_index] = layer_dict\n",
    "\n",
    "            else:  # 删除层\n",
    "                delete_index = random.randint(1, len(offspring['layer_list']) - 1)  # 删除位置\n",
    "                del offspring['layer_list'][delete_index]\n",
    "                offspring['layer_num'] -= 1\n",
    "\n",
    "        elif offspring['layer_num'] <= self.threshold:  # 小于等于临界值，只能添加或者替换\n",
    "            choice_index = random.randint(0, 1)\n",
    "            if mutation_layer_choice[choice_index] == 0:  # 添加\n",
    "                insert_index = random.randint(1, len(offspring['layer_list']) - 1)  # 插入位置\n",
    "                offspring['layer_list'].insert(insert_index, layer_dict)\n",
    "                offspring['layer_num'] += 1\n",
    "            else:\n",
    "                replace_index = random.randint(1, len(offspring['layer_list']) - 1)  # 替换位置\n",
    "                offspring['layer_list'][replace_index] = layer_dict\n",
    "\n",
    "        else:  # 层数到达最大值，则只能替换和删除\n",
    "            choice_index = random.randint(1, 2)\n",
    "            if mutation_layer_choice[choice_index] == 1:  # 替换层\n",
    "                replace_index = random.randint(1, len(offspring['layer_list']) - 1)  # 替换位置\n",
    "                offspring['layer_list'][replace_index] = layer_dict\n",
    "\n",
    "            else:  # 删除层\n",
    "                delete_index = random.randint(1, len(offspring['layer_list']) - 1)  # 删除位置\n",
    "                del offspring['layer_list'][delete_index]\n",
    "                offspring['layer_num'] -= 1\n",
    "        print('Mutation Operation:', mutation_layer_choice_name[choice_index])\n",
    "        return offspring\n",
    "\n",
    "    def get_best_chromosome(self, father, offspring1, offspring2, epochs):\n",
    "        \"\"\"\n",
    "        比较父代，子代1，子代2的适应度，返回适应度最大的染色体\n",
    "        :param father:\n",
    "        :param offspring1:\n",
    "        :param offspring2:\n",
    "        :param epochs:\n",
    "        :return: 返回适应度最高的染色体\n",
    "        \"\"\"\n",
    "        print('子代1训练：', epochs)\n",
    "        offspring1 = self.cal_fitness(offspring1, epochs)\n",
    "        \n",
    "        print('子代2训练：', epochs)\n",
    "        offspring2 = self.cal_fitness(offspring2, epochs)\n",
    "        \n",
    "        tmp_lines = [father, offspring1, offspring2]\n",
    "        sorted_lines = sorted(tmp_lines, key=operator.itemgetter('fitness'))  # 按适应度从小到大排序\n",
    "        return sorted_lines[-1]\n",
    "\n",
    "    def random_learning_rate(self):\n",
    "        return random.uniform(0.01, 0.02)  # 学习率\n",
    "\n",
    "    def random_select(self, ran_fit):\n",
    "        \"\"\"\n",
    "        轮盘赌选择\n",
    "        根据概率随机选择的染色体\n",
    "        :param ran_fit:\n",
    "        :return:\n",
    "        \"\"\"\n",
    "        ran = random.random()\n",
    "        for i in range(self.rows):\n",
    "            if ran < ran_fit[i]:\n",
    "                return i\n",
    "                \n",
    "                \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始迭代\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\SZU\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:203: UserWarning: Update your `MaxPooling2D` call to the Keras 2 API: `MaxPooling2D(pool_size=(2, 2), data_format=\"channels_last\")`\n",
      "C:\\Users\\SZU\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:203: UserWarning: Update your `MaxPooling2D` call to the Keras 2 API: `MaxPooling2D(pool_size=(3, 3), data_format=\"channels_last\")`\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "learning_rate: 0.012029467024930782\n",
      "layer_num: 4\n",
      "重新训练.......\n",
      "sparse_categorical_crossentropy\n",
      "Epoch 1/1\n",
      "22046/22046 [==============================] - 28s 1ms/step - loss: 7.5838 - acc: 0.5212\n",
      "5512/5512 [==============================] - 6s 1ms/step\n",
      "accuracy: 0.49038461538461536\n",
      "learning_rate: 0.015437717269751258\n",
      "layer_num: 4\n",
      "重新训练.......\n",
      "sparse_categorical_crossentropy\n",
      "Epoch 1/1\n",
      "22046/22046 [==============================] - 22s 1ms/step - loss: 7.7997 - acc: 0.5026\n",
      "5512/5512 [==============================] - 6s 1ms/step\n",
      "accuracy: 0.49038461538461536\n",
      "learning_rate: 0.01007904573168161\n",
      "layer_num: 5\n",
      "重新训练.......\n",
      "binary_crossentropy\n",
      "Epoch 1/1\n"
     ]
    }
   ],
   "source": [
    "# -------------入口函数，开始执行-----------------------------\n",
    "\"\"\"\n",
    "输入参数的的意义依次为\n",
    "        self.rows = rows                           # 染色体个数(即种群大小：101个网络)\n",
    "        self.times = times                         # 迭代次数\n",
    "        self.num_classes = num_classes             # 几分类\n",
    "        self.kill_num = kill_num                   # 每次迭代杀死的网络\n",
    "\"\"\"\n",
    "if __name__ == '__main__':\n",
    "    ga = GeneticAlgorithm(rows=50, times=3, num_classes=2, kill_num=7)\n",
    "    ga.run()\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
